<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DHP数据机密计算演示</title>
    <script src="./vue.js"></script>
    <script src="./wasm_exec.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            min-height: 100vh;
            padding: 20px;
            color: #333;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }

        /* 语言切换按钮样式 */
        .language-switcher {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1001;
        }
        .language-switcher button {
            background: #3498db;
            color: white;
            border: none;
            border-radius: 20px;
            padding: 8px 16px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s ease;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
        }
        .language-switcher button:hover {
            background: #2980b9;
            transform: translateY(-2px);
        }

        /* 消息通知样式 */
        .notification-container {
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            z-index: 1000;
            width: 90%;
            max-width: 500px;
        }

        .notification {
            background: white;
            border-radius: 8px;
            padding: 15px 20px;
            margin-bottom: 10px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            display: flex;
            align-items: center;
            justify-content: space-between;
            animation: slideDown 0.3s ease-out;
            border-left: 8px solid #3498db;
        }

        .notification.success {
            border-left-color: #2ecc71;
        }

        .notification.warning {
            border-left-color: #f39c12;
        }

        .notification.error {
            border-left-color: #e74c3c;
        }

        .notification.info {
            border-left-color: #3498db;
        }

        .notification-content {
            flex: 1;
            margin-right: 15px;
        }

        .notification-content.success {
            color: #2ecc71;
        }

        .notification-content.warning {
            color: #f39c12;
        }

        .notification-content.error {
            color: #e74c3c;
        }

        .notification-content.info {
            color: #3498db;
        }

        .notification-close {
            background: none;
            border: none;
            font-size: 1.2rem;
            cursor: pointer;
            color: #7f8c8d;
            transition: color 0.3s;
        }

        .notification-close:hover {
            color: #e74c3c;
        }

        @keyframes slideDown {
            from {
                opacity: 0;
                transform: translateY(-100%);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        @keyframes fadeOut {
            from {
                opacity: 1;
                transform: translateY(0);
            }
            to {
                opacity: 0;
                transform: translateY(-100%);
            }
        }

        .notification.fade-out {
            animation: fadeOut 0.3s ease-in forwards;
        }

        header {
            text-align: center;
            margin-bottom: 40px;
            padding: 30px;
            background: white;
            border-radius: 16px;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 15px;
            font-size: 2.5rem;
        }
        .subtitle {
            color: #7f8c8d;
            font-size: 1.3rem;
            max-width: 800px;
            margin: 0 auto;
            line-height: 1.6;
        }
        .subtitle.note {
            color: #f39c12;
            font-size: 1.1rem;
            margin: 0 auto;
        }
        .workflow {
            display: flex;
            justify-content: space-between;
            position: relative;
            margin-bottom: 50px;
        }
        .step {
            flex: 1;
            text-align: center;
            padding: 0 15px;
            position: relative;
            z-index: 2;
        }
        .step-number {
            width: 60px;
            height: 60px;
            background: #3498db;
            color: white;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.8rem;
            font-weight: bold;
            margin: 0 auto 20px;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);
        }
        .step.active .step-number {
            background: #e74c3c;
            transform: scale(1.15);
            box-shadow: 0 5px 15px rgba(231, 76, 60, 0.4);
        }
        .step-title {
            font-size: 1.3rem;
            font-weight: 600;
            margin-bottom: 15px;
            color: #2c3e50;
        }
        .step-desc-prefix {
            color: #2c3e50;
            font-weight: 600;
            font-size: 1.0rem;
            line-height: 1.5;
        }
        .step-desc-prefix.active {
            color: #e74c3c;
            font-weight: 800;
            font-size: 1.0rem;
            line-height: 1.5;
        }
        .step-desc {
            color: #7f8c8d;
            font-size: 0.95rem;
            line-height: 1.5;
        }
        .progress-bar {
            position: absolute;
            top: 30px;
            left: 0;
            width: 100%;
            height: 6px;
            background: #ddd;
            z-index: 1;
            border-radius: 3px;
        }
        .progress {
            height: 100%;
            background: linear-gradient(to right, #3498db, #e74c3c);
            width: 0%;
            transition: width 0.7s ease;
            border-radius: 3px;
        }

        /* 新布局样式 */
        .app-generation {
            display: flex;
            justify-content: center;
            margin-bottom: 10px;
        }
        .app-card {
            width: 48%;
            background: white;
            border-radius: 16px;
            padding: 25px;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease;
        }
        .app-card:hover {
            transform: translateY(-5px);
        }

        .computation-layout {
            display: flex;
            justify-content: space-between;
            align-items: stretch;
            margin-bottom: 40px;
            position: relative;
        }

        .data-provider {
            flex: 0 0 33.3%;
            max-width: 33.3%;
            display: flex;
            flex-direction: column;
        }

        .data-card {
            background: white;
            border-radius: 16px;
            padding: 25px;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease;
            height: 100%;
            display: flex;
            flex-direction: column;
        }
        .data-card:hover {
            transform: translateY(-5px);
        }

        .tee-center {
            flex: 1.2;
            display: flex;
            flex-direction: column;
            align-items: center;
            position: relative;
        }

        .arrow-to-tee {
            position: absolute;
            top: 50%;
            width: 100%;
            display: flex;
            justify-content: space-between;
            z-index: 5;
            pointer-events: none;
        }

        .arrow-left, .arrow-right {
            font-size: 3rem;
            color: #3498db;
            opacity: 0.7;
        }

        .arrow-left {
            margin-left: -40px;
        }

        .arrow-right {
            margin-right: -40px;
        }

        .tee-card {
            background: linear-gradient(135deg, #2c3e50 0%, #1a2530 100%);
            color: white;
            border-radius: 16px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
        }

        .card-title {
            font-size: 1.3rem;
            font-weight: 600;
            margin-bottom: 20px;
            padding-bottom: 15px;
            border-bottom: 3px solid #eee;
            color: #2c3e50;
            display: flex;
            align-items: center;
        }
        .tee-card .card-title {
            color: white;
            border-bottom-color: rgba(255,255,255,0.2);
        }
        .card-title i {
            margin-right: 12px;
            color: #e74c3c;
        }
        .tee-card .card-title i {
            color: #3498db;
        }
        .input-group {
            margin-bottom: 20px;
        }
        .input-group label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #2c3e50;
        }
        .tee-card .input-group label {
            color: white;
        }
        .input-group input {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 1rem;
            transition: border-color 0.3s;
        }
        .input-group input:focus {
            border-color: #3498db;
            outline: none;
        }
        .btn {
            padding: 12px 25px;
            border: none;
            border-radius: 8px;
            font-size: 1rem;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 10px;
        }
        .btn-primary {
            background: #3498db;
            color: white;
        }
        .btn-primary:hover {
            background: #2980b9;
        }
        .btn-secondary {
            background: #e74c3c;
            color: white;
        }
        .btn-secondary:hover {
            background: #c0392b;
        }
        .btn-success {
            background: #2ecc71;
            color: white;
        }
        .btn-success:hover {
            background: #27ae60;
        }
        .btn i {
            margin-right: 8px;
        }
        .btn:disabled {
            background: #bdc3c7;
            cursor: not-allowed;
        }
        .data-box {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin: 20px 0;
            font-family: monospace;
            position: relative;
            overflow: hidden;
            min-height: 100px;
            color: #2c3e50;
            flex-grow: 1;
        }
        .tee-card .data-box {
            background: rgba(255, 255, 255, 0.1);
            color: white;
        }
        .data-item {
            padding: 10px;
            border-bottom: 1px dashed #ddd;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .tee-card .data-item {
            border-bottom-color: rgba(255,255,255,0.2);
        }
        .data-item:last-child {
            border-bottom: none;
        }

        .info-box {
            background: rgba(255, 255, 255, 0.1);
            color: #fff;
            padding: 20px;
            border-radius: 10px;
            margin: 25px 0;
            font-size: 1rem;
            line-height: 1.6;
        }
        .info-box i {
            margin-right: 10px;
            color: #3498db;
        }
        .controls {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 40px;
        }
        .computation-step {
            padding: 15px;
            margin: 10px 0;
            background: rgba(255, 255, 255, 0.05);
            border-radius: 8px;
            text-align: left;
            display: flex;
            align-items: center;
        }
        .computation-step i {
            margin-right: 10px;
            color: #3498db;
        }
        .highlight {
            animation: highlight 1.5s ease;
        }
        @keyframes highlight {
            0% { background-color: transparent; }
            50% { background-color: rgba(52, 152, 219, 0.2); }
            100% { background-color: transparent; }
        }
        .result-badge {
            display: inline-block;
            padding: 5px 12px;
            background: #e74c3c;
            color: white;
            border-radius: 20px;
            font-size: 0.9rem;
            margin-left: 10px;
        }
        .success-badge {
            display: inline-block;
            padding: 5px 12px;
            background: #2ecc71;
            color: white;
            border-radius: 20px;
            font-size: 0.9rem;
            margin-left: 10px;
        }
        .app-hash {
            font-family: monospace;
            font-size: 0.9rem;
            word-break: break-all;
            color: #3498db;
            margin-top: 10px;
        }

		.data-flow {
		  display: flex;
		  justify-content: space-between;
		  align-items: center;
		  margin: 20px 0;
		}

		.arrow {
		  font-size: 24px;
		  color: #3498db;
		  animation: pulse 2s infinite;
		}

        /* 新增样式 */
        .trusted-app-box {
            background: #2ecc71;
            color: white;
            border-radius: 10px;
            padding: 15px;
            margin: 15px 0;
            text-align: center;
            font-weight: bold;
        }

        .ztdo-container {
            display: flex;
            justify-content: space-between;
            gap: 15px;
            margin: 15px 0;
        }

        .ztdo-box {
            border-radius: 10px;
            padding: 15px;
            text-align: center;
            font-weight: bold;
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 80px;
        }

        .kao-alice {
            background: rgba(224, 89, 26, 0.8);
            color: white;
        }

        .kao-bob {
            background: rgba(244, 81, 0, 0.8);
            color: white;
        }

        .ztdo-alice {
            background: rgba(52, 152, 219, 0.8);
            color: white;
        }

        .ztdo-bob {
            background: rgba(2, 146, 242, 0.8);
            color: white;
        }

        .key-item {
            padding: 8px;
            margin: 5px 0;
            background: rgba(255, 255, 255, 0.2);
            border-radius: 5px;
            font-family: monospace;
            font-size: 0.9rem;
            text-align: left;
            white-space: normal;
            overflow-wrap: break-word;
        }

        .dhp-step-btn {
            width: 100%;
            margin-top: 10px;
        }

        .note {
            font-size: 0.8rem;
            color: #95a5a6;
            margin-top: 20px;
            text-align: center;
        }

        .key-pair {
            margin: 10px 0;
            padding: 10px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 5px;
            transition: all 0.3s ease;
        }

        .key-pair-title {
            font-weight: bold;
            margin-bottom: 5px;
            color: #3498db;
        }

        .key-pair-additional-info {
            font-size: 0.85em;
            color: #99cbed;
            margin-bottom: 15px;
        }

        /* 新增的ZTDO封装动画样式 */
        .encryption-animation {
            position: relative;
            margin: 20px 0;
            padding: 15px;
            background: rgba(52, 152, 219, 0.1);
            border-radius: 10px;
            min-height: 200px;
        }

        .encryption-step {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            opacity: 0;
            transition: opacity 0.5s ease;
            padding: 15px;
        }

        .encryption-step.active {
            opacity: 1;
        }

        .key-visualization {
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 15px 0;
            width: 100%;
        }

        .key-item-visual {
            padding: 10px 15px;
            margin: 0 10px;
            background: #3498db;
            color: white;
            border-radius: 8px;
            font-weight: bold;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            animation: pulse 2s infinite;
        }

        .key-combination {
            display: flex;
            align-items: center;
            margin: 15px 0;
        }

        .plus-sign {
            margin: 0 15px;
            font-size: 1.5rem;
            color: #2c3e50;
        }

        .symmetric-key {
            padding: 12px 20px;
            background: #e74c3c;
            color: white;
            border-radius: 8px;
            font-weight: bold;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            animation: pulse 1.5s infinite;
        }

        .data-to-encrypt {
            padding: 12px 20px;
            background: #2ecc71;
            color: white;
            border-radius: 8px;
            font-weight: bold;
            margin: 15px 0;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }

        .encrypted-data {
            padding: 12px 20px;
            background: #9b59b6;
            color: white;
            border-radius: 8px;
            font-weight: bold;
            margin: 15px 0;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            animation: highlight 2s ease;
        }

        .arrow-down {
            font-size: 2rem;
            color: #3498db;
            margin: 10px 0;
        }

        /* 新增的红框高亮样式 */
        .highlight-red {
            animation: highlight-red 1.5s ease-in-out infinite alternate;
            border: 3px solid #e74c3c;
            box-shadow: 0 0 15px rgba(231, 76, 60, 0.5);
        }

        @keyframes highlight-red {
            0% { border-color: #e74c3c; box-shadow: 0 0 10px rgba(231, 76, 60, 0.5); }
            100% { border-color: #ff6b6b; box-shadow: 0 0 20px rgba(231, 76, 60, 0.8); }
        }

        .encryption-flow {
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 20px 0;
            flex-wrap: wrap;
        }

        .flow-item {
            margin: 10px;
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            position: relative;
        }

        .flow-arrow {
            font-size: 2rem;
            color: #3498db;
            margin: 0 10px;
        }

        .key-pair-flow {
            background: #3498db;
            color: white;
            min-width: 150px;
        }

        .symmetric-key-flow {
            background: #e74c3c;
            color: white;
            min-width: 120px;
        }

        .original-data-flow {
            background: #2ecc71;
            color: white;
            min-width: 120px;
        }

        .encrypted-data-flow {
            background: #9b59b6;
            color: white;
            min-width: 150px;
        }

        .flow-label {
            font-size: 0.8rem;
            margin-top: 5px;
            opacity: 0.9;
        }

        /* 新增的箭头连接样式 */
        .arrow-container {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 10;
        }

        .arrow-svg {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }

        .connection-controls {
            background: white;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 20px;
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }

        .connection-controls input {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            flex: 1;
            min-width: 200px;
        }

        .connection-controls button {
            padding: 8px 16px;
            background: #e74c3c;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background 0.3s;
        }

        .connection-controls button:hover {
            background: #c0392b;
        }

        .connection-controls button.delete {
            background: #ff4444;
        }

        .connection-controls button.delete:hover {
            background: #cc0000;
        }

        .connections-list {
            margin-top: 20px;
            background: white;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        .connection-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #eee;
        }

        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }

        @keyframes moveRight {
            0% { transform: translateX(0); }
            100% { transform: translateX(100px); }
        }

        @keyframes moveLeft {
            0% { transform: translateX(0); }
            100% { transform: translateX(-100px); }
        }

        @media (max-width: 1200px) {
            .computation-layout {
                flex-direction: column;
            }
            .arrow-to-tee {
                display: none;
            }
            .app-card {
                width: 80%;
            }
            .ztdo-container {
                flex-direction: column;
            }
            .encryption-flow {
                flex-direction: column;
            }
            .flow-arrow {
                transform: rotate(90deg);
                margin: 10px 0;
            }
        }
        @media (max-width: 768px) {
            .workflow {
                flex-direction: column;
                gap: 30px;
            }
            .progress-bar {
                display: none;
            }
            .app-card {
                width: 100%;
            }
            .key-visualization {
                flex-direction: column;
            }
            .key-item-visual {
                margin: 5px 0;
            }
            .connection-controls {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- 语言切换按钮 -->
        <div class="language-switcher">
            <button @click="switchLanguage">
                <i class="fas fa-globe"></i>
                {{ currentLanguage === 'zh' ? 'English' : '中文' }}
            </button>
        </div>

        <!-- 消息通知容器 -->
        <div class="notification-container">
            <div v-for="(notification, index) in notifications"
                 :key="notification.id"
                 :class="['notification', notification.type, notification.fadeOut ? 'fade-out' : '']">
                <div class="notification-content" :class="notification.type">
                    <i :class="getNotificationIcon(notification.type)" style="margin-right: 8px;"></i>
                    {{ notification.message }}
                </div>
                <button class="notification-close" @click="removeNotification(index)">
                    <i class="fas fa-times"></i>
                </button>
            </div>
        </div>

        <div class="container">
            <header>
                <h1>{{ texts.title }}</h1>
                <p class="subtitle">{{ texts.subtitle }}</p>
                <p class="subtitle note">{{ texts.note }}</p>
            </header>

            <div class="workflow">
                <div class="progress-bar">
                    <div class="progress" :style="{width: progressWidth}"></div>
                </div>
                <div class="step" :class="{active: currentStep >= 1}">
                    <div class="step-number">1</div>
                    <div class="step-title">{{ texts.step1Title }}</div>
                    <div class="step-desc"><span class="step-desc-prefix" :class="{active: currentStep == 1}">{{ texts.step1Prefix }}: </span>{{ texts.step1Desc }}</div>
                </div>
                <div class="step" :class="{active: currentStep >= 2}">
                    <div class="step-number">2</div>
                    <div class="step-title">{{ texts.step2Title }}</div>
                    <div class="step-desc"><span class="step-desc-prefix" :class="{active: currentStep == 2}">{{ texts.step2Prefix }}: </span>{{ texts.step2Desc }}</div>
                </div>
                <div class="step" :class="{active: currentStep >= 3}">
                    <div class="step-number">3</div>
                    <div class="step-title">{{ texts.step3Title }}</div>
                    <div class="step-desc"><span class="step-desc-prefix" :class="{active: currentStep == 3}">{{ texts.step3Prefix }}: </span>{{ texts.step3Desc }}</div>
                </div>
                <div class="step" :class="{active: currentStep >= 4}">
                    <div class="step-number">4</div>
                    <div class="step-title">{{ texts.step4Title }}</div>
                    <div class="step-desc"><span class="step-desc-prefix" :class="{active: currentStep == 4}">{{ texts.step4Prefix }}: </span>{{ texts.step4Desc }}</div>
                </div>
            </div>

            <!-- 可信应用生成部分 -->
            <div class="app-generation">
                <div class="app-card">
                    <div class="card-title">
                        <i class="fas fa-cube"></i> {{ texts.trustedAppTitle }}
                    </div>
                    <div class="input-group">
                        <label for="app-name">{{ texts.appNameLabel }}</label>
                        <input type="text" id="app-name" v-model="appName" placeholder="texts.appNamePlaceholder">
                    </div>
                    <button class="btn btn-success" @click="generateTrustedApp" :disabled="trustedAppGenerated">
                        <i class="fas fa-cogs"></i> {{ texts.deployTrustedApp }}
                    </button>

                    <div v-if="trustedAppGenerated">
                        <h3>{{ texts.trustedAppInfo }} <span class="success-badge">{{ texts.deployed }}</span></h3>
                        <div class="data-box">
                            <div class="data-item">
                                <span>{{ texts.appName }}</span>
                                <span>{{ appName }}</span>
                            </div>
                            <div class="data-item">
                                <span>{{ texts.appId }}</span>
                                <span>{{ appId }}</span>
                            </div>
                            <div class="data-item">
                                <span>{{ texts.deploymentTime }}</span>
                                <span>{{ deploymentTime }}</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="app-generation">
                <div><div class="arrow"><i class="fas fa-long-arrow-alt-down"></i></div></div>
            </div>

            <!-- 数据提供方和TEE布局 -->
            <div class="computation-layout" ref="computationLayout">
                <!-- 箭头容器 -->
				<div class="arrow-container">
				  <svg class="arrow-svg" ref="arrowSvg">
					<!-- 循环每个连接，添加key -->
					<template v-for="(conn, connIndex) in connections">
					  <!-- 每个连接只定义一次箭头头（共享相同颜色） -->
					  <defs>
						<marker
						  :id="`arrowhead-${connIndex}`"
						  markerWidth="10"
						  markerHeight="7"
						  refX="9"
						  refY="3.5"
						  orient="auto"
						>
						  <polygon points="0 0, 10 3.5, 0 7" :fill="conn.color" />
						</marker>
					  </defs>

					  <!-- 循环当前连接的所有路径，添加组合key确保唯一性 -->
					  <template v-for="(path, pathIndex) in conn.paths">
						<path
						  :d="path.d"
						  :stroke="conn.color"
						  stroke-width="2"
                          stroke-dasharray="10,5"
						  fill="none"
						  :marker-end="`url(#arrowhead-${connIndex})`"
						>
                            <animate v-if="isAliceEncrypting || isBobEncrypting || isAliceKAOEncrypting || isBobKAOEncrypting || (isDhpProcessing && currentDhpStep <= 4)"
                                attributeName="stroke-dashoffset"
                                from="15"
                                to="0"
                                dur="0.5s"
                                repeatCount="indefinite"
                            />
                        </path>
					  </template>
					</template>
				  </svg>
				</div>

                <!-- Alice数据提供方 -->
                <div class="data-provider">
                    <div class="data-card">
                        <div class="card-title">
                            <i class="fas fa-user-circle"></i> {{ texts.aliceTitle }}
                        </div>
                        <div class="input-group">
                            <label for="alice-data">{{ texts.aliceInputLabel }}</label>
                            <input type="text" id="alice-data" v-model="aliceInput" placeholder="texts.aliceInputPlaceholder" :disabled="!trustedAppGenerated || isAliceEncrypting">
                        </div>
                        <button class="btn btn-primary" @click="submitAliceData" :disabled="isAliceKAOEncrypting || isAliceEncrypting || !trustedAppGenerated || aliceEncodedData.length > 0">
                            <span v-if="isAliceKAOEncrypting"><i class="fas fa-cog fa-spin mr-2"></i>{{ texts.encryptingDataObjectPrivateKey }}</span>
                            <span v-else-if="isAliceEncrypting"><i class="fas fa-cog fa-spin mr-2"></i>{{ texts.encryptingZTDOData }}</span>
                            <span v-else><i class="fas fa-shield-alt"></i>{{ texts.encryptZTDOData }}</span>
                        </button>

                        <!-- 初始化时就显示的密钥对 -->
                        <div v-if="trustedAppGenerated">
                            <div class="data-box">
                                <div v-for="(pair, title) in aliceKeyPairs" :key="title"
                                     class="key-pair"
                                     :class="{'alice-data-object-key': getTitleFromKeyPair(title) === texts.dataObjectKeyPair}">
                                    <div class="key-pair-title">{{ getTitleFromKeyPair(title) }}</div>
                                    <div class="key-pair-additional-info">{{ getTitleAdditionalInfoFromKeyPair(title) }}</div>
                                    <div class="key-item"
                                        :class="{
                                            'highlight-red': currentEncryptStep === 2 && (getTitleFromKeyPair(title) === texts.dataObjectKeyPair) ||
                                                            currentEncryptStep === 1 && (getTitleFromKeyPair(title) === texts.teeKeyPair) ||
                                                            currentEncryptStep === 1 && (getTitleFromKeyPair(title) === texts.tempSessionKeyPair) ||
                                                            currentDhpStep === 1 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                            currentDhpStep === 2 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair)
                                        }">{{ texts.publicKey }}: {{ pair.publicKey }}</div>
                                    <div class="key-item"
                                        :class="{
                                            'highlight-red': currentEncryptStep === 2 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                             currentEncryptStep === 1 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                             currentDhpStep === 1 && (getTitleFromKeyPair(title) === texts.teeKeyPair) ||
                                                             currentDhpStep === 1 && (getTitleFromKeyPair(title) === texts.tempSessionKeyPair) ||
                                                             currentDhpStep === 2 && (getTitleFromKeyPair(title) === texts.dataObjectKeyPair)
                                        }">{{ texts.privateKey }}: {{ pair.privateKey }}</div>
                                </div>
                            </div>
                        </div>

                        <div v-if="isAliceKAOEncrypting">
                            <h3>{{ texts.dataObjectPrivateKeyEncapsulation }} <span class="result-badge">{{ texts.encapsulating }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data">{{ texts.kaoEncryptionDescription }}</div>
                            </div>
                        </div>

                        <div v-if="aliceEncodedKAO && !isAliceKAOEncrypting">
                            <h3>{{ texts.dataObjectPrivateKeyEncapsulation }} <span class="result-badge">{{ texts.encapsulated }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data">
                                <pre style="white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; max-width: 100%; padding: 1rem; border-radius: 6px;">{{ prettyJson(aliceEncodedKAO) }}</pre></div>
                            </div>
                        </div>

                        <div v-if="isAliceEncrypting">
                            <h3>{{ texts.ztdoEncapsulatedData }} <span class="result-badge">{{ texts.ztdoDataEncapsulating }}</span></h3>
                        </div>

                        <div v-if="aliceEncodedData && !isAliceEncrypting">
                            <h3>{{ texts.ztdoEncapsulatedData }} <span class="result-badge">{{ texts.encrypted }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data"><pre style="white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; max-width: 100%; padding: 1rem; border-radius: 6px;">{{ aliceEncodedData }}</pre></div>
                            </div>
                        </div>
                    </div>
                </div>

				<div class="data-flow"><div class="arrow"><i class="fas fa-long-arrow-alt-right"></i></div></div>

                <!-- TEE中心部分 -->
                <div class="tee-center">
                    <div class="tee-card">
                        <div class="card-title">
                            <i class="fas fa-shield-alt"></i> {{ texts.teeTitle }}
                        </div>

                        <!-- 可信应用框 -->
                        <div v-if="trustedAppGenerated" class="trusted-app-box">
                            <i class="fas fa-cube"></i> {{ texts.trustedApp }} {{ appId }}
                        </div>

                        <!-- ZTDO数据容器 - 将Alice和Bob的ZTDO数据放在同一行 -->
                        <div class="ztdo-container" v-if="aliceEncodedKAO || bobEncodedKAO || isAliceKAOEncrypting || isBobKAOEncrypting">
                            <!-- Alice ZTDO框 -->
                            <div v-if="aliceEncodedKAO || isAliceKAOEncrypting" class="ztdo-box kao-alice alice-kao-box">
                                <i class="fas fa-key"></i> {{ texts.aliceDataObjectPrivateKeyEncapsulation }}
                            </div>

                            <!-- Bob ZTDO框 -->
                            <div v-if="bobEncodedKAO || isBobKAOEncrypting" class="ztdo-box kao-bob bob-kao-box">
                                <i class="fas fa-key"></i> {{ texts.bobDataObjectPrivateKeyEncapsulation }}
                            </div>
                        </div>

                        <!-- ZTDO数据容器 - 将Alice和Bob的ZTDO数据放在同一行 -->
                        <div class="ztdo-container" v-if="aliceEncodedData || bobEncodedData || isAliceEncrypting || isBobEncrypting">
                            <!-- Alice ZTDO框 -->
                            <div v-if="aliceEncodedData || isAliceEncrypting" class="ztdo-box ztdo-alice alice-ztdo-box">
                                <i class="fas fa-lock"></i> {{ texts.aliceZTDOData }}
                            </div>

                            <!-- Bob ZTDO框 -->
                            <div v-if="bobEncodedData || isBobEncrypting" class="ztdo-box ztdo-bob bob-ztdo-box">
                                <i class="fas fa-lock"></i> {{ texts.bobZTDOData }}
                            </div>
                        </div>

                        <div class="info-box">
                            <i class="fas fa-info-circle"></i> {{ texts.teeDescription }}
                        </div>

                        <div v-if="currentStep < 4">
                            <div class="data-box">
                                <div v-if="currentStep === 1">{{ texts.waitingForTrustedApp }}</div>
                                <div v-else-if="currentStep === 2">{{ texts.waitingForAliceData }}</div>
                                <div v-else-if="currentStep === 3">{{ texts.waitingForBobData }}</div>
                            </div>
                        </div>
                        <div v-else>
                            <button class="btn btn-secondary dhp-step-btn" @click="nextDhpStep" :disabled="dhpStepCompleted || isDhpProcessing">
                                <i class="fas fa-forward"></i>
                                <span v-if="isDhpProcessing">{{ texts.processing }}</span>
                                <span v-else>{{ texts.nextDhpStep }}</span>
                            </button>

                            <div class="data-box">
                                <div v-if="currentDhpStep === 0">{{ texts.clickToStartDhp }}</div>
                                <div v-else>
                                    <div class="computation-step" v-for="(step, index) in dhpSteps" :key="index"
                                         :class="{highlight: index === currentDhpStep - 1}"
                                         :class="{dhp-active-step: index === currentDhpStep - 1}">
                                        <i class="fas fa-cog fa-spin" v-if="index === currentDhpStep - 1 && !dhpStepCompleted && !isCurrentStepComplete"></i>
                                        <i class="fas fa-check" v-else-if="(isCurrentStepComplete && index === (currentDhpStep - 1)) || index < currentDhpStep || (dhpStepCompleted && index < dhpSteps.length)"></i>
                                        <i class="fas fa-ellipsis-h" v-else></i>
                                        <span>{{ step }}</span>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div v-if="result.length > 0 && dhpStepCompleted">
                            <h3>{{ texts.intersectionResult }} <span class="success-badge">{{ texts.safelyReturned }}</span></h3>
                            <div class="data-box">
                                <div class="data-item" v-for="(num, index) in result" :key="index">
                                    <span>{{ texts.intersectionData }} {{ index + 1 }}</span>
                                    <span>{{ num }}</span>
                                </div>
                                <div class="data-item" v-if="result.length === 0">
                                    <span>{{ texts.noIntersectionData }}</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

				<div class="data-flow"><div class="arrow"><i class="fas fa-long-arrow-alt-left"></i></div></div>

                <!-- Bob数据提供方 -->
                <div class="data-provider">
                    <div class="data-card">
                        <div class="card-title">
                            <i class="fas fa-user-circle"></i> {{ texts.bobTitle }}
                        </div>
                        <div class="input-group">
                            <label for="bob-data">{{ texts.bobInputLabel }}</label>
                            <input type="text" id="bob-data" v-model="bobInput" placeholder="texts.bobInputPlaceholder" :disabled="!aliceEncodedData || isBobEncrypting">
                        </div>
                        <button class="btn btn-primary" @click="submitBobData" :disabled="!aliceEncodedData || isBobEncrypting || isBobKAOEncrypting || bobEncodedData.length > 0">
                            <span v-if="isBobKAOEncrypting"><i class="fas fa-cog fa-spin mr-2"></i>{{ texts.encryptingDataObjectPrivateKey }}</span>
                            <span v-else-if="isBobEncrypting"><i class="fas fa-cog fa-spin mr-2"></i>{{ texts.encryptingZTDOData }}</span>
                            <span v-else><i class="fas fa-shield-alt"></i>{{ texts.encryptZTDOData }}</span>
                        </button>

                        <!-- 初始化时就显示的密钥对 -->
                        <div v-if="aliceEncodedData">
                            <div class="data-box">
                                <div v-for="(pair, title) in bobKeyPairs" :key="title"
                                     class="key-pair"
                                     :class="{'bob-data-object-key': getTitleFromKeyPair(title) === texts.dataObjectKeyPair}">
                                    <div class="key-pair-title">{{ getTitleFromKeyPair(title) }}</div>
                                    <div class="key-pair-additional-info">{{ getTitleAdditionalInfoFromKeyPair(title) }}</div>
                                    <div class="key-item"
                                        :class="{
                                            'highlight-red': currentEncryptStep === 4 && (getTitleFromKeyPair(title) === texts.dataObjectKeyPair) ||
                                                            currentEncryptStep === 3 && (getTitleFromKeyPair(title) === texts.teeKeyPair) ||
                                                            currentEncryptStep === 3 && (getTitleFromKeyPair(title) === texts.tempSessionKeyPair) ||
                                                            currentDhpStep === 3 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                            currentDhpStep === 4 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair)
                                        }">{{ texts.publicKey }}: {{ pair.publicKey }}</div>
                                    <div class="key-item"
                                        :class="{
                                            'highlight-red': currentEncryptStep === 4 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                             currentEncryptStep === 3 && (getTitleFromKeyPair(title) === texts.dataProviderKeyPair) ||
                                                             currentDhpStep === 3 && (getTitleFromKeyPair(title) === texts.teeKeyPair) ||
                                                             currentDhpStep === 3 && (getTitleFromKeyPair(title) === texts.tempSessionKeyPair) ||
                                                             currentDhpStep === 4 && (getTitleFromKeyPair(title) === texts.dataObjectKeyPair)
                                        }">{{ texts.privateKey }}: {{ pair.privateKey }}</div>
                                </div>
                            </div>
                        </div>

                        <div v-if="isBobKAOEncrypting">
                            <h3>{{ texts.ztdoEncapsulatedData }} <span class="result-badge">{{ texts.ztdoDataEncapsulating }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data">{{ texts.ztdoEncryptionDescription }}</div>
                            </div>
                        </div>

                        <div v-if="bobEncodedKAO && !isBobKAOEncrypting">
                            <h3>{{ texts.dataObjectPrivateKeyEncapsulation }} <span class="result-badge">{{ texts.encapsulated }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data">
                                <pre style="white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; max-width: 100%; padding: 1rem; border-radius: 6px;">{{ prettyJson(bobEncodedKAO) }}</pre></div>
                            </div>
                        </div>

                        <div v-if="isBobEncrypting">
                            <h3>{{ texts.ztdoEncapsulatedData }} <span class="result-badge">{{ texts.ztdoDataEncapsulating }}</span></h3>
                        </div>

                        <div v-if="bobEncodedData && !isBobEncrypting">
                            <h3>{{ texts.ztdoEncapsulatedData }} <span class="result-badge">{{ texts.encrypted }}</span></h3>
                            <div class="data-box">
                                <div class="encoded-data"><pre style="white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; max-width: 100%; padding: 1rem; border-radius: 6px;">{{ bobEncodedData }}</pre></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="note">
                {{ texts.finalNote }}
            </div>

            <div class="controls">
                <button class="btn btn-primary" @click="prevStep" :disabled="currentStep === 1">
                    <i class="fas fa-arrow-left"></i> {{ texts.previousStep }}
                </button>
                <button class="btn btn-primary" @click="resetDemo">
                    <i class="fas fa-sync"></i> {{ texts.restart }}
                </button>
            </div>
        </div>
    </div>

    <script>
        // 语言包
        const languagePack = {
            zh: {
                headTitle: "DHP数据机密计算演示",
                title: "基于零信任DHP协议的隐私保护计算",
                subtitle: "基于DHP+可信执行环境(TEE)进行机密计算，在TEE中计算数据集的交集，保护数据隐私",
                note: "（演示用到的所有密钥对采用国密算法SM2生成）",
                step1Title: "可信应用部署",
                step1Prefix: "NHP代理",
                step1Desc: "创建并部署可信应用到TEE环境中",
                step2Title: "Alice数据封装",
                step2Prefix: "NHP数据经纪件",
                step2Desc: "Alice提供原始数据并进行ZTDO封装",
                step3Title: "Bob数据封装",
                step3Prefix: "NHP数据经纪件",
                step3Desc: "Bob提供原始数据并进行ZTDO封装",
                step4Title: "联合计算",
                step4Prefix: "NHP代理",
                step4Desc: "在TEE中进行联合计算并返回结果",
                trustedAppTitle: "可信应用Trust App",
                appNameLabel: "应用名称",
                appNamePlaceholder: "例如: 隐私求交应用",
                deployTrustedApp: "部署可信应用",
                trustedAppInfo: "可信应用信息",
                deployed: "已部署",
                appName: "应用名称",
                appId: "应用ID",
                deploymentTime: "部署时间",
                aliceTitle: "数据提供方 Alice",
                aliceInputLabel: "输入原始数据（逗号分隔）",
                aliceInputPlaceholder: "例如: 1, 3, 5, 7, 11",
                encryptingDataObjectPrivateKey: "数据对象私钥封装中...",
                encryptingZTDOData: "ZTDO数据封装中...",
                encryptZTDOData: "ZTDO数据封装",
                dataObjectPrivateKeyEncapsulation: "数据对象私钥封装",
                encapsulating: "封装中...",
                encapsulated: "已封装",
                ztdoEncapsulatedData: "ZTDO封装数据",
                ztdoDataEncapsulating: "ZTDO数据封装中...",
                encrypted: "已加密",
                dataObjectKeyPair: "数据对象密钥对",
                dataObjectKeyPairAdditionalInfo: "实现数据对象与密钥的一文一钥对应，为每个数据对象赋予独一无二的数字身份。",
                teeKeyPair: "TEE密钥对",
                teeKeyPairAdditionalInfo: "保证ZTDO数据对象只能在对应TEE环境中解密，确保数据隐私。",
                tempSessionKeyPair: "临时会话密钥对",
                tempSessionKeyPairAdditionalInfo: "实现数据对象的一用一密，赋予每一次数据对象的使用过程一个独一无二的授权密码，不可预测、不可重复使用",
                dataProviderKeyPair: "数据提供方密钥对",
                dataProviderKeyPairAdditionalInfo: "参与ZTDO数据对象加密和数据对象私钥的封装，从而明确数据主权的归属主体。",
                nhpAgentKeyPair: "NHP代理密钥对",
                nhpAgentKeyPairAdditionalInfo: "用于DHP消息的加密和签名，确保消息的安全性和完整性。",
                publicKey: "公钥",
                privateKey: "私钥",
                kaoEncryptionDescription: "使用数据对象提供方的私钥、TEE的公钥和临时公钥生成对称密钥，然后使用对称密钥对数据对象私钥进行加密封装",
                ztdoEncryptionDescription: "使用数据对象提供方的私钥和数据对象的私钥生成对称密钥，然后使用对称密钥对数据对象的原始数据进行加密",
                teeTitle: "可信执行环境 (TEE)",
                trustedApp: "可信应用",
                teeDescription: "在TEE中，数据被解密并执行计算，但任何人都无法从外部访问原始数据。",
                waitingForTrustedApp: "等待生成可信应用...",
                waitingForAliceData: "等待Alice数据封装完成...",
                waitingForBobData: "等待Bob数据封装完成...",
                nextDhpStep: "DHP协议下一步",
                processing: "处理中...",
                clickToStartDhp: "点击上方按钮开始DHP协议流程...",
                intersectionResult: "交集计算结果",
                safelyReturned: "安全返回",
                intersectionData: "交集数据",
                noIntersectionData: "无交集数据",
                aliceDataObjectPrivateKeyEncapsulation: "Alice 数据对象私钥封装",
                bobDataObjectPrivateKeyEncapsulation: "Bob 数据对象私钥封装",
                aliceZTDOData: "Alice ZTDO数据",
                bobZTDOData: "Bob ZTDO数据",
                bobTitle: "数据提供方 Bob",
                bobInputLabel: "输入原始数据（逗号分隔）",
                bobInputPlaceholder: "例如: 2, 3, 5, 13",
                previousStep: "上一步",
                restart: "重新开始",
                finalNote: "注意：在实际系统中，ZTDO封装所涉及的私钥是严格保密的，可信执行环境中的私钥是系统启动的时候自动生成的，即使管理员也无法获取到私钥。此演示页面展示的公私钥仅用于展示DHP技术原理。",
                appNameInputAlert: "请输入应用名称",
				aliceInputAlert: "请输入Alice的数据",
				bobInputAlert: "请输入Bob的数据",
				ztdoEncryptFailedAlert: "数据封装失败",
				dataPrkEncapFailedAlert: "数据对象私钥封装失败",
				genKeyPairFailedAlert: "生成密钥对失败",
				aliceDataPrkDecryptFailedAlert: "解封Alice数据对象私钥封装失败",
				aliceUnexpectedDecryptedDataPrkAlert: "解封Alice数据对象私钥封装成功，但与预期不符",
				aliceDataDecryptFailedAlert: "解密Alice ZTDO数据封装失败",
				aliceUnexpectedDecryptedDataAlert: "解密Alice ZTDO数据封装成功，但与预期不符",
				bobDataPrkDecryptFailedAlert: "解封Bob数据对象私钥封装失败",
				bobUnexpectedDecryptedDataPrkAlert: "解封Bob数据对象私钥封装成功，但与预期不符",
				bobDataDecryptFailedAlert: "解密Bob ZTDO数据封装失败",
				bobUnexpectedDecryptedDataAlert: "解密Bob ZTDO数据封装成功，但与预期不符",
				wasmLoadAlert: "等待Wasm模块加载完成",
				genTrustAppNotification: "可信应用部署成功后，自动开始Alice的数据对象私钥封装。",
				aliceZTDOFinishNotification: "Alice ZTDO封装完成之后，自动开始Bob的数据对象私钥封装。",
				aliceDataPrkDecryptFinishNotification: "解封Alice数据对象私钥封装成功，数据对象私钥：",
				aliceDataDecryptFinishNotification: "解密Alice ZTDO数据封装成功，原始数据：",
				bobDataPrkDecryptFinishNotification: "解封Bob数据对象私钥封装成功，数据对象私钥：",
				bobDataDecryptFinishNotification: "解密Bob ZTDO数据封装成功，原始数据："
            },
            en: {
                headTitle: "DHP Based Privacy-Preserving Computation Demonstration",
                title: "Privacy-Preserving Computation Based on Zero-Trust DHP Protocol",
                subtitle: "Using DHP + Trusted Execution Environment (TEE) for confidential computing, computing dataset intersections in TEE to protect data privacy",
                note: "(All key pairs used in this demo are generated using the SM2 national cryptographic algorithm)",
                step1Title: "Trusted Application Deployment",
                step1Prefix: "NHP Agent",
                step1Desc: "Create and deploy trusted application to TEE environment",
                step2Title: "Alice Data Encapsulation",
                step2Prefix: "NHP Data Broker",
                step2Desc: "Alice provides raw data and performs ZTDO encapsulation",
                step3Title: "Bob Data Encapsulation",
                step3Prefix: "NHP Data Broker",
                step3Desc: "Bob provides raw data and performs ZTDO encapsulation",
                step4Title: "Joint Computation",
                step4Prefix: "NHP Agent",
                step4Desc: "Perform joint computation in TEE and return results",
                trustedAppTitle: "Trusted Application",
                appNameLabel: "Application Name",
                appNamePlaceholder: "e.g., Private Set Intersection App",
                deployTrustedApp: "Deploy Trusted Application",
                trustedAppInfo: "Trusted Application Information",
                deployed: "Deployed",
                appName: "Application Name",
                appId: "Application ID",
                deploymentTime: "Deployment Time",
                aliceTitle: "Data Provider Alice",
                aliceInputLabel: "Input Raw Data (comma-separated)",
                aliceInputPlaceholder: "e.g., 1, 3, 5, 7, 11",
                encryptingDataObjectPrivateKey: "Encapsulating Data Object Private Key...",
                encryptingZTDOData: "Encrypting ZTDO Data...",
                encryptZTDOData: "Encrypt ZTDO Data",
                dataObjectPrivateKeyEncapsulation: "Data Object Private Key Encapsulation",
                encapsulating: "Encapsulating...",
                encapsulated: "Encapsulated",
                ztdoEncapsulatedData: "ZTDO Encapsulated Data",
                ztdoDataEncapsulating: "ZTDO Data Encapsulating...",
                encrypted: "Encrypted",
                dataObjectKeyPair: "Data Object Key Pair",
                dataObjectKeyPairAdditionalInfo: "Realize the 'one data object, one key' correspondence between data objects and keys, and endow each data object with a unique digital identity.",
                teeKeyPair: "TEE Key Pair",
                teeKeyPairAdditionalInfo: "Ensure that ZTDO data objects can only be decrypted in corresponding TEE environment to guarantee data privacy.",
                tempSessionKeyPair: "Temporary Session Key Pair",
                tempSessionKeyPairAdditionalInfo: "Realize the 'one use, one key' for data objects, and assign a unique authorization password to each usage process of the data object, which is unpredictable and non-reusable.",
                dataProviderKeyPair: "Data Provider Key Pair",
                dataProviderKeyPairAdditionalInfo: "Participate in the encryption of ZTDO data objects and the encapsulation of data object private keys, so as to clarify the subject of data sovereignty ownership.",
                nhpAgentKeyPair: "NHP Agent Key Pair",
                nhpAgentKeyPairAdditionalInfo: "Used for the encryption and signature of DHP messages to ensure the security and integrity of messages.",
                publicKey: "Public Key",
                privateKey: "Private Key",
                kaoEncryptionDescription: "Using the data provider's private key, TEE's public key, and temporary public key to generate a symmetric key, then using the symmetric key to encrypt the data object private key",
                ztdoEncryptionDescription: "Using the data provider's private key and data object's private key to generate a symmetric key, then using the symmetric key to encrypt the raw data of the data object",
                teeTitle: "Trusted Execution Environment (TEE)",
                trustedApp: "Trusted Application",
                teeDescription: "In TEE, data is decrypted and computation is performed, but no one can access the raw data from outside.",
                waitingForTrustedApp: "Waiting for trusted application generation...",
                waitingForAliceData: "Waiting for Alice data encapsulation...",
                waitingForBobData: "Waiting for Bob data encapsulation...",
                nextDhpStep: "Next DHP Protocol Step",
                processing: "Processing...",
                clickToStartDhp: "Click the button above to start DHP protocol flow...",
                intersectionResult: "Intersection Result",
                safelyReturned: "Safely Returned",
                intersectionData: "Intersection Data",
                noIntersectionData: "No Intersection Data",
                aliceDataObjectPrivateKeyEncapsulation: "Alice Data Object Private Key Encapsulation",
                bobDataObjectPrivateKeyEncapsulation: "Bob Data Object Private Key Encapsulation",
                aliceZTDOData: "Alice ZTDO Data",
                bobZTDOData: "Bob ZTDO Data",
                bobTitle: "Data Provider Bob",
                bobInputLabel: "Input Raw Data (comma-separated)",
                bobInputPlaceholder: "e.g., 2, 3, 5, 13",
                previousStep: "Previous Step",
                restart: "Restart",
                finalNote: "Note: In actual systems, the private keys involved in ZTDO encapsulation are strictly confidential. The private keys in the trusted execution environment are automatically generated when the system starts up, and even administrators cannot access them. The public and private keys displayed on this demo page are only for demonstrating DHP technical principles.",
                aliceInputAlert: "Please enter Alice's data",
                bobInputAlert: "Please enter Bob's data",
                ztdoEncryptFailedAlert: "Data encapsulation failed",
                dataPrkEncapFailedAlert: "Failed to encapsulate the private key of the data object",
                genKeyPairFailedAlert: "Failed to generate key pair",
                aliceDataPrkDecryptFailedAlert: "Failed to decapsulate the private key encapsulation of Alice's data object",
                aliceUnexpectedDecryptedDataPrkAlert: "Successfully decapsulated the private key encapsulation of Alice's data object, but it does not match the expectation",
                aliceDataDecryptFailedAlert: "Failed to decrypt Alice's ZTDO data encapsulation",
                aliceUnexpectedDecryptedDataAlert: "Successfully decrypted Alice's ZTDO data encapsulation, but it does not match the expectation",
                bobDataPrkDecryptFailedAlert: "Failed to decapsulate the private key encapsulation of Bob's data object",
                bobUnexpectedDecryptedDataPrkAlert: "Successfully decapsulated the private key encapsulation of Bob's data object, but it does not match the expectation",
                bobDataDecryptFailedAlert: "Failed to decrypt Bob's ZTDO data encapsulation",
                bobUnexpectedDecryptedDataAlert: "Successfully decrypted Bob's ZTDO data encapsulation, but it does not match the expectation",
                wasmLoadAlert: "Please wait for the Wasm module to load before proceeding.",
                genTrustAppNotification: "After the trusted app is successfully deployed, the encapsulation of Alice's data object private key will start automatically.",
                aliceZTDOFinishNotification: "After the encapsulation of Alice's ZTDO is completed, the encapsulation of Bob's data object private key will start automatically.",
                aliceDataPrkDecryptFinishNotification: "Successfully decapsulate the private key encapsulation of Alice's data object. Private key of the data object:",
                aliceDataDecryptFinishNotification: "Successfully decrypt Alice's ZTDO data encapsulation. Original data:",
                bobDataPrkDecryptFinishNotification: "Successfully decapsulate the private key encapsulation of Bob's data object. Private key of the data object:",
                bobDataDecryptFinishNotification: "Successfully decrypt Bob's ZTDO data encapsulation. Original data:"
            }
        };

        new Vue({
            el: '#app',
            data: {
                currentLanguage: 'zh',
                texts: languagePack['zh'],
                notifications: [],
                notificationId: 0,
                currentStep: 1,
                trustedAppGenerated: false,
                appName: "INTERSECT(SetA, SetB)",
                appId: "",
                deploymentTime: "",
                appHash: "",
                aliceInput: "1,3,5,7,11",
                bobInput: "2,3,5,13",
                aliceData: [],
                bobData: [],
                aliceEncodedData: "",
                bobEncodedData: "",
                aliceEncodedKAO: "",
                bobEncodedKAO: "",
                // 初始化时就生成密钥对
                aliceKeyPairs: {},
                bobKeyPairs: {},
                result: [],
                currentDhpStep: 0,
                currentEncryptStep: 0,
                dhpStepCompleted: false,
                isDhpProcessing: false,
                dhpSteps: [
                    "解封Alice数据对象私钥封装",
                    "解密Alice ZTDO数据封装",
                    "解封Bob数据对象私钥封装",
                    "解密Bob ZTDO数据封装",
                    "调用可信应用执行机密计算",
                    "审核计算结果",
                    "返回安全结果"
                ],
                // 新增的加密动画状态
                isAliceEncrypting: false,
                isBobEncrypting: false,
                isAliceKAOEncrypting: false,
                isBobKAOEncrypting: false,
                isCurrentStepComplete: false,

                // 箭头连接相关数据
                fromClass: '.highlight-red',
                toClass: '.alice-kao-box',
                arrowColor: '#6961ffff',
                connections: [],
                stepDelay: 500,

                // 其他
                isWasmLoaded: false,
            },
            computed: {
                progressWidth() {
                    if (this.currentStep >= 4) {
                        return '100%';
                    } else {
                        return ((this.currentStep - 1) / 3) * 100 + '%';
                    }
                }
            },
            mounted() {
                // 监听窗口大小变化
                window.addEventListener('resize', this.updateAllArrows);

                // 监听步骤变化，更新箭头
                this.$watch('currentDhpStep', this.updateArrowsDuringDhpSteps);
                this.$watch('currentEncryptStep', this.updateArrowsDuringEncryptSteps);

                this.initWasm()
            },
            updated() {
                document.title = this.texts.headTitle
            },
            methods: {
                switchLanguage() {
                    this.currentLanguage = this.currentLanguage === 'zh' ? 'en' : 'zh';
                    this.texts = languagePack[this.currentLanguage];

                    // 更新DHP步骤描述
                    if (this.currentLanguage === 'en') {
                        this.dhpSteps = [
                            "Unseal Alice Data Object Private Key Encapsulation",
                            "Decrypt Alice ZTDO Data Encapsulation",
                            "Unseal Bob Data Object Private Key Encapsulation",
                            "Decrypt Bob ZTDO Data Encapsulation",
                            "Call Trusted App for Confidential Computing",
                            "Audit Computation Results",
                            "Return Secure Results"
                        ];
                    } else {
                        this.dhpSteps = [
                            "解封Alice数据对象私钥封装",
                            "解密Alice ZTDO数据封装",
                            "解封Bob数据对象私钥封装",
                            "解密Bob ZTDO数据封装",
                            "调用可信应用执行机密计算",
                            "审核计算结果",
                            "返回安全结果"
                        ];
                    }
                },

                showNotification(message, type = 'info', duration = 5000) {
                    const id = this.notificationId++;
                    const notification = {
                        id,
                        message,
                        type,
                        duration,
                        fadeOut: false
                    };

                    this.notifications.push(notification);

                    // 自动移除通知
                    setTimeout(() => {
                        this.removeNotificationById(id);
                    }, duration);
                },

                removeNotification(index) {
                    if (index >= 0 && index < this.notifications.length) {
                        this.notifications.splice(index, 1);
                    }
                },

                removeNotificationById(id) {
                    const index = this.notifications.findIndex(n => n.id === id);
                    if (index !== -1) {
                        // 先添加淡出动画
                        this.notifications[index].fadeOut = true;

                        // 动画完成后移除
                        setTimeout(() => {
                            const fadeIndex = this.notifications.findIndex(n => n.id === id);
                            if (fadeIndex !== -1) {
                                this.notifications.splice(fadeIndex, 1);
                            }
                        }, 300);
                    }
                },

                getNotificationIcon(type) {
                    switch(type) {
                        case 'success': return 'fas fa-check-circle';
                        case 'warning': return 'fas fa-exclamation-triangle';
                        case 'error': return 'fas fa-exclamation-circle';
                        case 'info':
                        default: return 'fas fa-info-circle';
                    }
                },

                generateUUID() {
                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                        const r = Math.random() * 16 | 0;
                        const v = c === 'x' ? r : (r & 0x3 | 0x8);
                        return v.toString(16);
                    });
                },

                async initWasm() {
                    const go = new Go() // 初始化Go环境
                    // 加载main.wasm并执行
                    const result = await WebAssembly.instantiateStreaming(
                        fetch('./main.wasm'), // 确保main.wasm路径正确
                        go.importObject
                    )
                    go.run(result.instance) // 启动Go程序，此时Go暴露的函数已挂载到window

                    this.isWasmLoaded = true
                },
                prettyJson(jsonStr) {
                    try {
                        const jsonObj = JSON.parse(jsonStr)
                        return JSON.stringify(jsonObj, null, 2)
                    } catch (err) {
                        return "JSON格式错误: " + err.message
                    }
                },
                async generateTrustedApp() {
                    if (!this.appName) {
                        alert(this.texts.appNameInputAlert);
                        return;
                    }

                    if (!this.isWasmLoaded) {
                        alert(this.texts.wasmLoadAlert);
                        return;
                    }

                    // 模拟生成可信应用
                    this.appId = this.generateUUID();
                    this.deploymentTime = new Date().toLocaleString();
                    this.appHash = this.generateHash(64);
                    this.trustedAppGenerated = true;

                    this.showNotification(this.texts.genTrustAppNotification);

                    // 初始化Alice的密钥对
                    this.aliceKeyPairs = this.generateKeyPairs();

                    // 开始Alice数据对象私钥封装
                    this.currentEncryptStep++;
                    this.isAliceKAOEncrypting = true;

                    this.aliceEncodedKAO = await this.encryptDataObjectPrivateKey(
                        this.aliceKeyPairs["tee"].publicKey,
                        this.aliceKeyPairs["temp"].publicKey,
                        this.aliceKeyPairs["dataProvider"].privateKey,
                        this.aliceKeyPairs["dataObject"].privateKey
                    );

                    this.isAliceKAOEncrypting = false;
                    // 更新箭头位置
                    this.$nextTick(() => {
                        this.updateAllArrows();
                    });

                    // 自动进入下一步
                    if (this.currentStep === 1) {
                        this.currentStep = 2;
                    }
                },

                async submitAliceData() {
                    if (!this.aliceInput) {
                        alert(this.texts.aliceInputAlert);
                        return;
                    }

                    // 解析输入的数据
                    this.aliceData = this.aliceInput.split(',')
                        .map(item => item.trim())
                        .filter(item => item !== "")
                        .map(Number);

                    // 开始加密Alice ZTDO数据封装
                    this.isAliceEncrypting = true;
                    this.currentEncryptStep++;

                    // ZTDO封装过程
                    this.aliceEncodedData = await this.encyptData(
                        this.aliceKeyPairs["dataObject"].publicKey,
                        this.aliceKeyPairs["dataProvider"].privateKey,
                        this.aliceInput
                    );

                    // 完成加密
                    this.isAliceEncrypting = false;

                    // 初始化Bob的密钥对（在Alice加密完成后）
                    this.bobKeyPairs = this.generateKeyPairs();

                    this.showNotification(this.texts.aliceZTDOFinishNotification);

                    // 开始Bob数据对象私钥封装
                    this.isBobKAOEncrypting = true;
                    this.currentEncryptStep++;

                    this.bobEncodedKAO = await this.encryptDataObjectPrivateKey(
                        this.bobKeyPairs["tee"].publicKey,
                        this.bobKeyPairs["temp"].publicKey,
                        this.bobKeyPairs["dataProvider"].privateKey,
                        this.bobKeyPairs["dataObject"].privateKey
                    );

                    this.isBobKAOEncrypting = false;
                    // 更新箭头位置
                    this.$nextTick(() => {
                        this.updateAllArrows();
                    })

                    // 自动进入下一步
                    if (this.currentStep === 2) {
                        this.currentStep = 3;
                    }
                },

                async submitBobData() {
                    if (!this.bobInput) {
                        alert(this.texts.bobInputAlert);
                        return;
                    }

                    // 解析输入的数据
                    this.bobData = this.bobInput.split(',')
                        .map(item => item.trim())
                        .filter(item => item !== "")
                        .map(Number);

                    // 开始加密Bob ZTDO数据封装
                    this.isBobEncrypting = true;
                    this.currentEncryptStep++;

                    // ZTDO封装过程
                    this.bobEncodedData = await this.encyptData(
                        this.bobKeyPairs["dataObject"].publicKey,
                        this.bobKeyPairs["dataProvider"].privateKey,
                        this.bobInput
                    );

                    // 完成加密
                    this.isBobEncrypting = false;

                    // 自动进入下一步
                    if (this.currentStep === 3) {
                        this.currentStep = 4;
                    }

                    // 更新箭头位置
                    this.$nextTick(() => {
                        this.updateAllArrows();
                    })
                },

                async encyptData(dataPub, providerPrk, data) {
                    const res = window.encryptDataFromGo(
                        dataPub,
                        providerPrk,
                        data
                    );

                    if (!res.success) {
                        alert(this.texts.ztdoEncryptFailedAlert);
                        return "";
                    }

                    await this.delay(this.stepDelay);

                    return res.cipherText;
                },

                async encryptDataObjectPrivateKey(teePub, tempPub, providerPrk, dataPrk) {
                    const res = window.encapsulateDataPrkFromGo(
                        teePub,
                        tempPub,
                        providerPrk,
                        dataPrk
                    );

                    if (!res.success) {
                        alert(this.texts.dataPrkEncapFailedAlert);
                        return "";
                    }

                    await this.delay(this.stepDelay);

                    return res.dataPrkWrappingJson;
                },

                generateKeyPairs() {
                    // 生成5对演示密钥对，使用字典格式
                    const providerKeyPair = window.generateSM2KeyPairFromGo();
                    const dataObjectKeyPair = window.generateSM2KeyPairFromGo();
                    const nhpAgentKeyPair = window.generateSM2KeyPairFromGo();
                    const teeKeyPair = window.generateSM2KeyPairFromGo();
                    const tempSessionKeyPair = window.generateSM2KeyPairFromGo();

                    if (!providerKeyPair.success || !dataObjectKeyPair.success || !nhpAgentKeyPair.success || !teeKeyPair.success || !tempSessionKeyPair.success) {
                        alert(this.texts.genKeyPairFailedAlert);
                        return {};
                    }

                    return {
                        "dataProvider": {
                            publicKey: providerKeyPair.pub,
                            privateKey: providerKeyPair.prk
                        },
                        "dataObject": {
                            publicKey: dataObjectKeyPair.pub,
                            privateKey: dataObjectKeyPair.prk
                        },
                        "nhpAgent": {
                            publicKey: nhpAgentKeyPair.pub,
                            privateKey: nhpAgentKeyPair.prk
                        },
                        "tee": {
                            publicKey: teeKeyPair.pub,
                            privateKey: teeKeyPair.prk
                        },
                        "temp": {
                            publicKey: tempSessionKeyPair.pub,
                            privateKey: tempSessionKeyPair.prk
                        }
                    };
                },

                getTitleFromKeyPair(key) {
                    if (key === "nhpAgent") {
                        return this.texts.nhpAgentKeyPair;
                    } else if (key === "tee") {
                        return this.texts.teeKeyPair;
                    } else if (key === "temp") {
                        return this.texts.tempSessionKeyPair;
                    } else if (key === "dataProvider") {
                        return this.texts.dataProviderKeyPair;
                    } else if (key === "dataObject") {
                        return this.texts.dataObjectKeyPair;
                    }
                },

                getTitleAdditionalInfoFromKeyPair(key) {
                    if (key === "nhpAgent") {
                        return this.texts.nhpAgentKeyPairAdditionalInfo;
                    } else if (key === "tee") {
                        return this.texts.teeKeyPairAdditionalInfo;
                    } else if (key === "temp") {
                        return this.texts.tempSessionKeyPairAdditionalInfo;
                    } else if (key === "dataProvider") {
                        return this.texts.dataProviderKeyPairAdditionalInfo;
                    } else if (key === "dataObject") {
                        return this.texts.dataObjectKeyPairAdditionalInfo;
                    }
                },

                generateHash(length) {
                    const chars = '0123456789abcdef';
                    let result = '';
                    for (let i = length; i > 0; --i) {
                        result += chars[Math.floor(Math.random() * chars.length)];
                    }
                    return result;
                },

                // DHP协议步骤处理函数
                async processDhpStep(stepIndex) {
                    this.isDhpProcessing = true;
                    this.isCurrentStepComplete = false

                    // 根据步骤索引调用相应的处理函数
                    switch(stepIndex) {
                        case 1: // 解封Alice数据对象私钥封装
                            await this.unsealAliceKAO();
                            break;
                        case 2: // 解密Alice ZTDO数据封装
                            await this.decryptAliceZTDO();
                            break;
                        case 3: // 解封Bob数据对象私钥封装
                            await this.unsealBobKAO();
                            break;
                        case 4: // 解密Bob ZTDO数据封装
                            await this.decryptBobZTDO();
                            break;
                        case 5: // 调用可信应用执行机密计算
                            await this.executeTrustedApp();
                            break;
                        case 6: // 审核计算结果
                            await this.auditResult();
                            break;
                        case 7: // 返回安全结果
                            await this.returnSecureResult();
                            break;
                    }

                    this.isDhpProcessing = false;
                    this.isCurrentStepComplete = true;

                    // 更新箭头位置
                    this.updateAllArrows();
                },

                // 解封Alice数据对象私钥封装
                async unsealAliceKAO() {
                    const res = window.decapsulateDataPrkFromGo(
                        this.aliceKeyPairs["tee"].privateKey,
                        this.aliceKeyPairs["temp"].privateKey,
                        this.aliceEncodedKAO
                    )

                    if (!res.success) {
                        alert(this.texts.aliceDataPrkDecryptFailedAlert);
                        return;
                    }

                    if (!(this.aliceKeyPairs["dataObject"].privateKey === res.dataPrkBase64)) {
                        alert(this.texts.aliceUnexpectedDecryptedDataPrkAlert);
                        return;
                    }

                    // 模拟处理延迟
                    await this.delay(this.stepDelay);

                    this.showNotification(this.texts.aliceDataPrkDecryptFinishNotification + res.dataPrkBase64 + "。");
                },

                // 解密Alice ZTDO数据封装
                async decryptAliceZTDO() {
                    const res = window.decryptDataFromGo(
                        this.aliceKeyPairs["dataObject"].privateKey,
                        this.aliceKeyPairs["dataProvider"].publicKey,
                        this.aliceEncodedData
                    )

                    if (!res.success) {
                        alert(this.texts.aliceDataDecryptFailedAlert);
                        return;
                    }

                    if (!(this.aliceInput === res.rawData)) {
                        alert(this.texts.aliceUnexpectedDecryptedDataAlert);
                        return;
                    }

                    // 模拟处理延迟
                    await this.delay(this.stepDelay);

                    this.showNotification(this.texts.aliceDataDecryptFinishNotification + res.rawData + "。");
                },

                // 解封Bob数据对象私钥封装
                async unsealBobKAO() {
                    const res = window.decapsulateDataPrkFromGo(
                        this.bobKeyPairs["tee"].privateKey,
                        this.bobKeyPairs["temp"].privateKey,
                        this.bobEncodedKAO
                    )

                    if (!res.success) {
                        alert(this.texts.bobDataPrkDecryptFailedAlert);
                        return;
                    }

                    if (!(this.bobKeyPairs["dataObject"].privateKey === res.dataPrkBase64)) {
                        alert(this.texts.bobUnexpectedDecryptedDataPrkAlert);
                        return;
                    }

                    // 模拟处理延迟
                    await this.delay(this.stepDelay);

                    this.showNotification(this.texts.bobDataPrkDecryptFinishNotification + res.dataPrkBase64 + "。");
                },

                // 解密Bob ZTDO数据封装
                async decryptBobZTDO() {
                    const res = window.decryptDataFromGo(
                        this.bobKeyPairs["dataObject"].privateKey,
                        this.bobKeyPairs["dataProvider"].publicKey,
                        this.bobEncodedData
                    )

                    if (!res.success) {
                        alert(this.texts.bobDataDecryptFailedAlert);
                        return;
                    }

                    if (!(this.bobInput === res.rawData)) {
                        alert(this.texts.bobUnexpectedDecryptedDataAlert);
                        return;
                    }

                    // 模拟处理延迟
                    await this.delay(this.stepDelay);

                    this.showNotification(this.texts.bobDataDecryptFinishNotification + res.rawData + "。");
                },

                // 调用可信应用执行机密计算
                async executeTrustedApp() {
                    this.result = this.aliceData.filter(value => this.bobData.includes(value));

                    // 模拟处理延迟
                    await this.delay(this.stepDelay);
                },

                // 审核计算结果
                async auditResult() {
                    await this.delay(this.stepDelay);
                },

                // 返回安全结果
                async returnSecureResult() {
                    // 模拟处理延迟
                    await this.delay(this.stepDelay);
                },

                // 通用延迟函数
                delay(ms) {
                    return new Promise(resolve => setTimeout(resolve, ms));
                },

                async nextDhpStep() {
                    if (this.currentDhpStep === 0) {
                        this.currentEncryptStep++;
                    }

                    if (this.currentDhpStep < this.dhpSteps.length && !this.isDhpProcessing) {
                        // 处理当前DHP步骤
                        this.currentDhpStep++;

                        await this.processDhpStep(this.currentDhpStep);

                        // 如果是最后一步，计算交集并标记所有步骤完成
                        if (this.currentDhpStep === this.dhpSteps.length) {
                            this.dhpStepCompleted = true;
                        }
                    }
                },

                nextStep() {
                    if (this.currentStep < 4) {
                        this.currentStep++;
                    }
                },

                prevStep() {
                    if (this.currentStep > 1) {
                        this.currentStep--;
                        this.currentDhpStep = 0;
                        this.dhpStepCompleted = false;
                        this.isDhpProcessing = false;

                        // 重置相关状态
                        if (this.currentStep === 1) {
                            this.trustedAppGenerated = false;
                            this.aliceEncodedKAO = "";
                            this.currentEncryptStep = 0;
                        } else if (this.currentStep === 2) {
                            this.aliceEncodedData = "";
                            this.bobEncodedKAO = "";
                            this.currentEncryptStep -= 2;
                            this.bobKeyPairs = {};
                        } else if (this.currentStep === 3) {
                            this.bobEncodedData = "";
                            this.currentEncryptStep -= 2;
                            this.result = [];
                        }

                        // 更新箭头位置
                        this.updateAllArrows();
                    }
                },

                resetDemo() {
                    this.currentStep = 1;
                    this.trustedAppGenerated = false;
                    this.appName = "INTERSECT(SetA, SetB)";
                    this.appId = "";
                    this.deploymentTime = "";
                    this.appHash = "";
                    this.aliceData = [];
                    this.bobData = [];
                    this.aliceEncodedData = "";
                    this.bobEncodedData = "";
                    this.aliceKeyPairs = {};
                    this.bobKeyPairs = {};
                    this.result = [];
                    this.currentDhpStep = 0;
                    this.currentEncryptStep = 0;
                    this.isDhpProcessing = false;
                    this.dhpStepCompleted = false;
                    this.isAliceEncrypting = false;
                    this.isBobEncrypting = false;
                    this.aliceEncodedKAO = "";
                    this.bobEncodedKAO = "";

                    // 重置连接
                    this.connections = [];
                },

                // 箭头连接相关方法
                addConnection(fromClass, toClass, color) {
                    if (!fromClass || !toClass) return;

                    const newConnection = {
                        from: fromClass,
                        to: toClass,
                        color: color,
                        paths: []
                    };

                    this.connections.push(newConnection);
                    this.updateConnectionPaths(newConnection);
                },

                removeConnection(index) {
                    this.connections.splice(index, 1);
                },

                clearConnections() {
                    this.connections = [];
                },

                updateArrowPath(connection) {
                    const fromEl = document.querySelector(connection.from);
                    const toEl = document.querySelector(connection.to);
                    const container = this.$refs.computationLayout;

                    if (!fromEl || !toEl || !container) return;

                    const containerRect = container.getBoundingClientRect();
                    const fromRect = fromEl.getBoundingClientRect();
                    const toRect = toEl.getBoundingClientRect();

                    // 计算相对于容器的中心点
                    const fromX = fromRect.left + fromRect.width / 2 - containerRect.left;
                    const fromY = fromRect.top + fromRect.height / 2 - containerRect.top;
                    const toX = toRect.left + toRect.width / 2 - containerRect.left;
                    const toY = toRect.top + toRect.height / 2 - containerRect.top;

                    // 更新路径
                    connection.path = `M ${fromX} ${fromY} L ${toX} ${toY}`;
                },

				// 更新单个连接的所有路径（处理多源元素）
                updateConnectionPaths(connection) {
                    const container = this.$refs.computationLayout;
                    if (!container) return;

                    // 获取所有匹配的源元素和目标元素
                    const fromEls = document.querySelectorAll(connection.from);
                    const toEl = document.querySelector(connection.to); // 假设目标元素唯一

                    // 清空现有路径
                    connection.paths = [];

                    // 如果没有源元素或目标元素，直接返回
                    if (fromEls.length === 0 || !toEl) return;

                    const containerRect = container.getBoundingClientRect();
                    const toRect = toEl.getBoundingClientRect();

                    // 计算目标元素左右边缘中间点相对于容器的位置
                    const toRightX = toRect.right - containerRect.left;
                    const toLeftX = toRect.left - containerRect.left;
                    const toMiddleY = toRect.top + toRect.height / 2 - containerRect.top;

                    // 为每个源元素生成路径
                    fromEls.forEach((fromEl, index) => {
                        const fromRect = fromEl.getBoundingClientRect();

                        // 计算源元素左右边缘中间点相对于容器的位置
                        const fromRightX = fromRect.right - containerRect.left;
                        const fromLeftX = fromRect.left - containerRect.left;
                        const fromMiddleY = fromRect.top + fromRect.height / 2 - containerRect.top;

                        // 判断源元素在目标元素的左侧还是右侧
                        const fromIsLeftOfTo = fromRect.right < toRect.left;

                        // 根据位置确定箭头起点和终点
                        let startX, startY, endX, endY;
                        if (fromIsLeftOfTo) {
                            // 源元素在左侧：从源元素左边缘中间到目标元素右边缘中间
                            startX = fromRightX;
                            startY = fromMiddleY;
                            endX = toLeftX;
                            endY = toMiddleY;
                        } else {
                            // 源元素在右侧：从源元素右边缘中间到目标元素左边缘中间
                            startX = fromLeftX;
                            startY = fromMiddleY;
                            endX = toRightX;
                            endY = toMiddleY;
                        }

                        // 添加路径信息
                        connection.paths.push({
                            id: `${connection.id}-path-${index}`,
                            fromEl: fromEl,
                            d: `M ${startX} ${startY} L ${endX} ${endY}` // 路径数据
                        });
                    });
                },

                updateAllArrows() {
                    this.$nextTick(() => {
                        this.connections.forEach(conn => {
                            this.updateConnectionPaths(conn);
                        });
                    });
                },

                updateArrowsDuringDhpSteps() {
                    this.clearConnections();
                    if (this.currentDhpStep <= 4) {
                        this.addConnection('.highlight-red', '.computation-step.highlight', this.arrowColor);
                    }
                },

                updateArrowsDuringEncryptSteps() {
                    if (this.currentEncryptStep <= 4) {
                        this.clearConnections();
                    }

                    switch(this.currentEncryptStep) {
                        case 1: // 封装Alice数据对象私钥
                            this.addConnection('.highlight-red', '.alice-kao-box', this.arrowColor);
                            break;
                        case 2: // 封装Alice ZTDO数据封装
                            this.addConnection('.highlight-red', '.alice-ztdo-box', this.arrowColor);
                            break;
                        case 3: // 封装Bob数据对象私钥
                            this.addConnection('.highlight-red', '.bob-kao-box', this.arrowColor);
                            break;
                        case 4: // 封装Bob ZTDO数据封装
                            this.addConnection('.highlight-red', '.bob-ztdo-box', this.arrowColor);
                            break;
                    }
                }
            }
        });
    </script>
</body>
</html>